﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
using System.IO;
using System.ComponentModel;

namespace Performance
{
    /**
     * Multimedia Retrieval
     * Heat Kernel Signature project
     * Frank Borgonjen, Joeri van der Lei & Kevin van der Lei
     * 28-10-2011
     * 
     * This is the main class for the Performance Measure application. It initializes the application window
     * and distributes the data among the other classes.
     */
    public static class Program
    {
        private static Chart chart;
        private static OpenFileDialog fileSelect;
        private static PerformanceWindow form1;
        private static String distance_file_csv;
        private static string[] comboValues = new string[] { Analyzer.PR, Analyzer.ROC };
        private static double[][] distances;
        private static string[] fileNames;

        /**
         * This method initialized the form.
         */
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            form1 = new PerformanceWindow();
            Application.Run(form1);
        }

        /**
         * When a distance matrix file is selected, this method is called. It reads the distance file
         * and calculates the performance for the file.
         * 
         * @param sender The object that invoked this method
         * @param args The arguments necessary for when the file selection is cancelled
         */
        public static void fileSelected(object sender, CancelEventArgs args)
        {
            fileSelect          = (OpenFileDialog) sender;
            distance_file_csv   = @fileSelect.FileName;

            distances           = getDistances();
            fileNames           = getFileNames();

            // Show Precision Recall graph
            showGraph(Analyzer.PR);

            // set one number measure
            form1.setLabel("1sttier", Analyzer.kthTier(distances, fileNames, 1));
            form1.setLabel("2ndtier", Analyzer.kthTier(distances, fileNames, 2));
            form1.setLabel("BEP", Analyzer.BEP(distances, fileNames));
            form1.setLabel("avgprec", Analyzer.avgPrec(distances, fileNames));
        }

        /**
         * Reads the distance matrix file and returns a useable distance matrix
         */
        private static double[][] getDistances()
        {
            TextReader reader = new StreamReader(distance_file_csv);
            string line = reader.ReadLine();
            int nrRows = line.Split(',').Length - 1;
            string[] split;
            double[][] distances = new double[nrRows][];
            int rowCount = 0;
            while ((line = reader.ReadLine()) != null)
            {
                split = line.Split(',');
                double[] distance = new double[nrRows];
                double d;
                for (int i = 1; i <= nrRows; i++)
                {
                    String s = split[i];
                    Double.TryParse(s, out d);
                    distance[i - 1] = d;
                }
                distances[rowCount++] = distance;
            }
            return distances;
        }

        /**
         * Stores all filenames in a local variable so we can use that to filter
         * the categories from the filenames.
         */
        private static string[] getFileNames()
        {
            TextReader reader   = new StreamReader(distance_file_csv);
            string line         = reader.ReadLine();
            string[] split      = line.Split(',');
            string[] names      = new string[split.Length - 1];
            for (int i = 1; i < split.Length; i++)
            {
                names[i - 1] = split[i];
            }
            return names;
        }

        /**
         * This method is called when someone changed the value for the combobox
         * for the graph type
         * 
         * @param sender The object that invoked this method
         * @param e The arguments that belong to the call
         */
        public static void graphTypeChanged(object sender, System.EventArgs e)
        {
            ComboBox combo  = (ComboBox)sender;
            string val      = comboValues[combo.SelectedIndex];
            showGraph(val);
        }

        /**
         * fetches the performance results and fetches the right graph according to the given type
         * 
         * @param performanceType The type of the graph to show
         */
        public static void showGraph(string performanceType)
        {
            Dictionary<double, double> points = Analyzer.performance(distances, fileNames, performanceType);
            chart = form1.getChart();
            chart.Series["PR"].Points.Clear();
            chart.Series["PR"].Points.AddXY(0, 1);
            foreach (KeyValuePair<double, double> kvp in points)
            {
                chart.Series["PR"].Points.AddXY(kvp.Key, kvp.Value);
            }
            chart.Series["PR"].Points.AddXY(1, 0);
            form1.Refresh();
        }
    }
}
